library flutter_vcard;

import 'dart:math';
import 'dart:ui';

import 'package:flutter/material.dart';

typedef NextCallback(int index);
typedef PreviousCallback(int index);
typedef SwipeCallback(int index);

typedef IndexChangeCallback(int index);
typedef EndCallback();

typedef CardIndexedWidgetBuilder = Widget Function(
  BuildContext context,
  int index,
  int cardIndex,
);

typedef IndexedOffsetBuilder = Offset Function(
  BuildContext context,
  int index,
  int cardIndex,
);

class VCardView extends StatefulWidget {
  /// 是否循环
  final bool loop;

  /// Offset

  /// 卡片尺寸
  final Size itemSize;

  /// 缩放比例，默认 0.03
  final double expandScales;

  /// 子项数量
  final int itemCount;

  /// 是否打开手势
  final bool enablePointer;

  /// 构建子项布局
  final CardIndexedWidgetBuilder itemBuild;

  final Offset? card2Offset;

  final Offset card3Offset;

  /// 滑动速度（非零，默认1.3）
  final double slideSpeed;

  /// 控制器
  final VCardController? controller;

  /// 下一页回调
  final NextCallback? nextCallback;

  /// 上一页回调
  final PreviousCallback? previousCallback;

  /// swipe away回调
  final SwipeCallback? swipeCallback;

  /// 下标改变的回调
  final IndexChangeCallback? indexChangeCallback;

  /// 最后一个结束的回调
  final EndCallback? endCallback;
  final EdgeInsetsGeometry? padding;

  VCardView({
    Key? key,
    required this.itemSize,
    required this.itemCount,
    required this.itemBuild,
    this.loop = false,
    this.expandScales = 0.03,
    this.enablePointer = true,
    this.slideSpeed = 1.3,
    this.controller,
    this.nextCallback,
    this.previousCallback,
    this.indexChangeCallback,
    this.endCallback,
    this.swipeCallback,
    this.card2Offset,
    this.padding,
    Offset? card3Offset,
  })  : this.card3Offset = card3Offset ?? Offset(0, 11),
        super(key: key);

  @override
  State<VCardView> createState() => _VCardViewState();
}

class _VCardViewState extends State<VCardView> with TickerProviderStateMixin {
  //  最前面卡片的索引
  int _frontCardIndex = 0;

  int get frontCardIndex => _frontCardIndex;

  // 滑动时的偏移量
  double _pageOffsetY = 0.0;

  // 将要进到下一页
  bool _willNext = false;

  // 将要进到上一页
  bool _willPrevious = false;

  bool _willDismiss = false;

  // 动画控制器
  late AnimationController _animationControllerY;

  late AnimationController _animationControllerX;

  // 动画
  late Animation<double> _animationY;
  late Animation<double> _animationX;

  double _pageOffsetX = 0.0;

  // 滑动的动画
  Animation<double> _slideAnimation(
      AnimationController controller, double begin,
      {double end = 0}) {
    // double end = 0;
    if (_pageOffsetY < 0) {
      //1、不loop
      //2、是最后一个
      //3、滑动不超过一半
      end = (!widget.loop && _frontCardIndex == widget.itemCount - 1) ||
              (_pageOffsetY.abs() < widget.itemSize.height * 0.5)
          ? 0
          : -widget.itemSize.height;
    } else if (_pageOffsetY > 0) {
      end = (!widget.loop && _frontCardIndex == 0) ||
              (_pageOffsetY.abs() < widget.itemSize.height * 0.5)
          ? 0
          : widget.itemSize.height;
    }

    return _animationControllerY
        .drive(CurveTween(curve: Curves.linear))
        .drive(Tween<double>(begin: _pageOffsetY, end: end))
      ..addListener(() {
        _pageOffsetY = _animationY.value;
        // _setPageOffsetYLimit();

        // 下一页&上一页
        if (_pageOffsetY < 0) {
          _willNext = true;
          _willPrevious = false;
        } else if (_pageOffsetY > 0) {
          _willNext = false;
          _willPrevious = true;
        } else {
          _willNext = false;
          _willPrevious = false;
        }
        setState(() {});
      })
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          _pageOffsetY = 0;

          // 进入下一页
          if (_willNext) {
            _frontCardIndex++;
            // 下标最大值

            if (_frontCardIndex >= widget.itemCount) {
              _frontCardIndex = widget.loop ? 0 : widget.itemCount - 1;
            }
            // 结束了的回调
            if (!widget.loop) {
              if (_frontCardIndex >= widget.itemCount - 1) {
                if (widget.endCallback != null &&
                    widget.endCallback is Function) {
                  widget.endCallback!();
                }
              }
            }

            // 下一页回调
            if (widget.nextCallback != null &&
                widget.nextCallback is Function) {
              widget.nextCallback!(_frontCardIndex);
            }
          }

          // 进入上一页
          if (_willPrevious) {
            _frontCardIndex--;
            // 下标最小值
            if (_frontCardIndex < 0) {
              _frontCardIndex = !widget.loop ? 0 : widget.itemCount - 1;
            }
            // 上一页回调
            if (widget.previousCallback != null &&
                widget.previousCallback is Function) {
              widget.previousCallback!(_frontCardIndex);
            }
          }

          // 下标改变回调
          if ((_willNext || _willPrevious) &&
              widget.indexChangeCallback != null &&
              widget.indexChangeCallback is Function) {
            widget.indexChangeCallback!(_frontCardIndex);
          }

          // 清空下一页&上一页状态
          _willNext = false;
          _willPrevious = false;
          setState(() {});
        }
      });
  }

  // 滑动的动画
  Animation<double> _slideAnimationX(
      AnimationController controller, double begin,
      {double end = 0}) {
    // double end = 0;
    if (_pageOffsetX < 0) {
      end = (_pageOffsetX.abs() < widget.itemSize.width * 0.5)
          ? 0
          : -widget.itemSize.width;
    } else if (_pageOffsetX > 0) {
      end = (_pageOffsetX.abs() < widget.itemSize.width * 0.5)
          ? 0
          : widget.itemSize.width;
    }
    return _animationControllerX
        .drive(CurveTween(curve: Curves.easeIn))
        .drive(Tween<double>(begin: _pageOffsetX, end: end))
      ..addListener(() {
        _pageOffsetX = min(widget.itemSize.width,
            (max(-widget.itemSize.width, _animationX.value)));
        // _setPageOffsetXLimit();

        // 下一页&上一页
        if (_pageOffsetX < 0) {
          _willDismiss = true;
        } else if (_pageOffsetX > 0) {
          _willDismiss = true;
        } else {
          _willDismiss = false;
        }
        setState(() {});
      })
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          _pageOffsetX = 0;

          // 进入上一页
          if (_willDismiss) {
            widget.swipeCallback
                ?.call(min(_frontCardIndex, widget.itemCount - 1));

            _frontCardIndex--;
            // 下标最小值
            if (_frontCardIndex < 0) {
              _frontCardIndex = 0;
            }
          }

          // 下标改变回调
          if (_willDismiss &&
              widget.indexChangeCallback != null &&
              widget.indexChangeCallback is Function) {
            widget.indexChangeCallback!(_frontCardIndex);
          }

          // 清空下一页&上一页状态
          _willDismiss = false;
          setState(() {});
        }
      });
  }

  // 开始滑动的动画
  _startSlideAnimationY(Animation<double> animation) {
    _animationY = animation;
    _animationControllerY.reset();
    _animationControllerY.forward();
  }

  // 开始滑动的动画
  _startSlideAnimationX(Animation<double> animation) {
    _animationX = animation;
    _animationControllerX.reset();
    _animationControllerX.forward();
  }

  // 垂直方向停止滑动事件，开始执行动画
  _onEndPanVerticalAnimation(DragEndDetails details) {
    final halfOfHeight = widget.itemSize.height * 0.5;
    // if (_pageOffsetY.abs() < halfOfHeight) {
    //   double velocity =
    //       details.velocity.pixelsPerSecond.dy / window.devicePixelRatio;
    //   if (velocity < -halfOfHeight) {
    //     _pageOffsetY = -halfOfHeight - 10;
    //   } else if (velocity > halfOfHeight) {
    //     _pageOffsetY = halfOfHeight + 10;
    //   }
    // }
    _animationY = _slideAnimation(_animationControllerY, _pageOffsetY);
    _startSlideAnimationY(_animationY);
  }

  // 横向方向停止滑动事件，开始执行动画
  _onEndPanHorizontalAnimation(DragEndDetails details) {
    final halfOfWidth = widget.itemSize.width * 0.5;
    if (_pageOffsetX.abs() < halfOfWidth) {
      double velocity =
          details.velocity.pixelsPerSecond.dx / window.devicePixelRatio;
      if (velocity < -halfOfWidth) {
        _pageOffsetX = -halfOfWidth - 10;
      } else if (velocity > halfOfWidth) {
        _pageOffsetX = halfOfWidth + 10;
      }
    }
    _animationX = _slideAnimationX(_animationControllerX, _pageOffsetX);
    _startSlideAnimationX(_animationX);
  }

  // 第 0 页，超过屏幕，在上部的，不缩放，初始透明度 0
  Widget _card0() {
    if (!widget.loop && _frontCardIndex < 1) {
      return SizedBox();
    }
    int index =
        (_frontCardIndex > 1 && (_frontCardIndex - 1) < widget.itemCount)
            ? (_frontCardIndex - 1)
            : widget.loop
                ? (_frontCardIndex - 1 + widget.itemCount) % (widget.itemCount)
                : 0;

    double offsetY = -widget.itemSize.height;
    if (_pageOffsetY < 0) {
    } else if (_pageOffsetY > 0) {
      offsetY = -widget.itemSize.height -
          2 * widget.expandScales * widget.itemSize.height / 2 +
          _pageOffsetY;
    }

    double offsetX = -widget.itemSize.width;
    if (_pageOffsetX < 0) {
    } else if (_pageOffsetX > 0) {
      offsetX = -widget.itemSize.width -
          2 * widget.expandScales * widget.itemSize.width / 2 +
          _pageOffsetX;
    }

    return TransformView(
      opacity: (_pageOffsetY > 0)
          ? min(_pageOffsetY / widget.itemSize.height, 1)
          : 0,
      // : (_pageOffsetX > 0 ? _pageOffsetX / widget.size.width : 0),
      offset: Offset(0, offsetY),
      size: widget.itemSize,
      child: widget.itemBuild(context, index, 0),
    );
  }

  // 第 1 页，刚开始显示的页面，不缩放，初始透明度 1
  Widget _card1() {
    if (!widget.loop && _frontCardIndex > widget.itemCount - 1) {
      return SizedBox();
    }
    int index = _frontCardIndex < widget.itemCount ? _frontCardIndex : 0;
    double scales = 1 - 0 * widget.expandScales;
    double offsetY = 0;

    double aY = (_pageOffsetY / widget.itemSize.height);
    scales = scales - aY * widget.expandScales;
    if (_pageOffsetY < 0) {
      offsetY = offsetY + _pageOffsetY;
    } else if (_pageOffsetY > 0) {
      offsetY = offsetY + _pageOffsetY * aY * widget.expandScales;
    }

    double offsetX = 0;
    //去除默认的横向偏移量
    // - 2 * widget.expandScales * widget.size.width / 2;

    double aX = (_pageOffsetX / widget.itemSize.width);
    scales = scales - aX * widget.expandScales;
    if (_pageOffsetX < 0) {
      offsetX = offsetX + _pageOffsetX;
    } else if (_pageOffsetX > 0) {
      //right 向右移动
      offsetX = offsetX + _pageOffsetX;

      // 通过差速
      // offsetX = offsetX + _pageOffsetX * aX * widget.expandScales;
    }

    return TransformView(
      opacity: 1,
      // min(1, max(0.0, 1.0 + 0.5 * _pageOffsetY / widget.itemSize.height)),
      offset: Offset(offsetX, offsetY),
      size: widget.itemSize,
      scale: scales,
      child: widget.itemBuild(context, index, 1),
    );
  }

  // 第 2 页，第一页的后面一页，初始缩放 1 * widget.expandScales ，偏移
  Widget _card2() {
    if (!widget.loop && _frontCardIndex > widget.itemCount - 2) {
      return SizedBox();
    }
    int index = (_frontCardIndex + 1) < widget.itemCount
        ? (_frontCardIndex + 1)
        : widget.loop
            ? (_frontCardIndex + 1 + widget.itemCount) % (widget.itemCount)
            : 1;
    double scales = 1 - 1 * widget.expandScales;
    double offsetY = (widget.card2Offset?.dy ?? 6.67) / scales;

    double aY = (_pageOffsetY / widget.itemSize.height);
    scales = scales - aY * widget.expandScales;
    if (_pageOffsetY < 0) {
      offsetY = offsetY - _pageOffsetY * aY * widget.expandScales;
    } else if (_pageOffsetY > 0) {
      offsetY = offsetY + _pageOffsetY * aY * widget.expandScales;
    }

    //x方向左右滑动 底层的widget放大处理 向上抬的感觉
    double offsetX = (1 - scales) / 2 * widget.itemSize.width -
        widget.expandScales * widget.itemSize.width / 2;
    double aX = (_pageOffsetX.abs() / widget.itemSize.width);
    scales = scales + aX * widget.expandScales;

    offsetX = offsetX - _pageOffsetX.abs() * aX * widget.expandScales;

    return TransformView(
      opacity: 1.0,
      offset: Offset(0, offsetY),
      scale: scales,
      size: widget.itemSize,
      child: widget.itemBuild(context, index, 2),
    );
  }

  // 第 3 页，第二页的后面一页，初始缩放 2 * widget.expandScales ，偏移
  Widget _card3() {
    if (!widget.loop && _frontCardIndex > widget.itemCount - 3) {
      return SizedBox();
    }
    int index = (_frontCardIndex + 2) < widget.itemCount
        ? (_frontCardIndex + 2)
        : widget.loop
            ? (_frontCardIndex + 2 + widget.itemCount) % widget.itemCount
            : 2;
    double scales = 1 - 2 * widget.expandScales;
    double offsetY = widget.card3Offset.dy / scales;

    double aY = (_pageOffsetY / widget.itemSize.height);
    scales = scales - aY * widget.expandScales;
    if (_pageOffsetY < 0) {
      offsetY = offsetY - _pageOffsetY * aY * widget.expandScales;
    } else if (_pageOffsetY > 0) {
      // offsetY = offsetY + _pageOffsetY * a * widget.expandScales;
    }

    double offsetX = (1 - scales) / 2 * widget.itemSize.width;

    double aX = (_pageOffsetX.abs() / widget.itemSize.width);
    scales = scales + aX * widget.expandScales;
    offsetX = offsetX - _pageOffsetX.abs() * aX * widget.expandScales;

    return TransformView(
      opacity: 1.0,
      scale: scales,
      offset: Offset(0, offsetY),
      size: widget.itemSize,
      child: widget.itemBuild(context, index, 3),
    );
  }

  // 第 4 页，第三页的后面一页，初始缩放 3 * widget.expandScales ，偏移和3一样
  Widget _card4() {
    if (!widget.loop && _frontCardIndex > widget.itemCount - 4) {
      return SizedBox();
    }
    int index = (_frontCardIndex + 3) < widget.itemCount
        ? (_frontCardIndex + 3)
        : widget.loop
            ? (_frontCardIndex + 3 + widget.itemCount) % widget.itemCount
            : 3;
    double scales = 1 - 3 * widget.expandScales;
    double offsetY = 11;

    double aY = (_pageOffsetY / widget.itemSize.height);
    scales = scales - aY * widget.expandScales;
    if (_pageOffsetY < 0) {
      offsetY = offsetY - _pageOffsetY * aY * widget.expandScales / 2;
    } else if (_pageOffsetY > 0) {
      //   // offsetY = offsetY + _pageOffsetY * a * widget.expandScales;
    }

    double offsetX = (1 - scales) / 2 * widget.itemSize.width - 0;

    double aX = (_pageOffsetX / widget.itemSize.width);
    scales = scales - aX * widget.expandScales;
    if (_pageOffsetX < 0) {
      offsetX = offsetX - _pageOffsetX * aX * widget.expandScales / 2;
    } else if (_pageOffsetX > 0) {
      //   // offsetY = offsetY + _pageOffsetY * a * widget.expandScales;
    }

    return TransformView(
      opacity: _pageOffsetY >= 0 || _pageOffsetX >= 0 ? 0.0 : 1.0,
      scale: scales,
      offset: Offset(0, offsetY),
      size: widget.itemSize,
      child: widget.itemBuild(context, index, 4),
    );
  }

  // 设置 pageOffsetY 的各种情况下 值的 范围
  // _setPageOffsetYLimit() {
  //   // 当第一页时下拉是往前看一页，此时是没有上一页的，故设置不能超过翻页的标准
  //   if (_frontCardIndex == 0 && _pageOffsetY > 0) {
  //     _pageOffsetY = min(_pageOffsetY, widget.itemSize.height * 0.8);
  //   }
  //   // 当最后一页时上拉是看下一页，此时是没有下一页的，故设置不能超过翻页的标准
  //   if (_frontCardIndex == widget.itemCount - 1 && _pageOffsetY < 0) {
  //     _pageOffsetY = max(_pageOffsetY, -widget.itemSize.height * 0.8);
  //   }
  //   // 最小值
  //   if (_pageOffsetY <= -widget.itemSize.height) {
  //     _pageOffsetY = -widget.itemSize.height;
  //   }
  //   // 最大值
  //   if (_pageOffsetY >= widget.itemSize.height) {
  //     _pageOffsetY = widget.itemSize.height;
  //   }
  // }

  // 设置 pageOffsetY 的各种情况下 值的 范围
  _setPageOffsetXLimit() {
    // 当第一页时下拉是往前看一页，此时是没有上一页的，故设置不能超过翻页的标准
    if (_frontCardIndex == 0 && _pageOffsetX > 0) {
      _pageOffsetX = min(_pageOffsetX, widget.itemSize.width / 2 - 50);
    }
    // 当最后一页时上拉是看下一页，此时是没有下一页的，故设置不能超过翻页的标准
    if (_frontCardIndex == widget.itemCount - 1 && _pageOffsetX < 0) {
      _pageOffsetX = max(_pageOffsetX, -widget.itemSize.width / 2 + 50);
    }
    // 最小值
    if (_pageOffsetX <= -widget.itemSize.width) {
      _pageOffsetX = -widget.itemSize.width;
    }
    // 最大值
    if (_pageOffsetX >= widget.itemSize.width) {
      _pageOffsetX = widget.itemSize.width;
    }
  }

  Widget _gestureView() {
    return SizedBox.expand(
      child: GestureDetector(
        onHorizontalDragDown: (details) {
          // print('垂直--->down--->$details');
          _animationControllerX.stop();
        },
        onHorizontalDragUpdate: (details) {
          _pageOffsetX += (details.delta.dx * widget.slideSpeed);
          // _setPageOffsetXLimit();
          setState(() {});
        },

        onHorizontalDragEnd: (details) {
          _onEndPanHorizontalAnimation(details);
        },

        // 垂直滑动
        onVerticalDragDown: (details) {
          // print('垂直--->down--->$details');
          _animationControllerY.stop();
        },
        onVerticalDragStart: (details) {
          // print('垂直--->start--->${_pageOffsetY}');
        },
        onVerticalDragUpdate: (details) {
          _pageOffsetY += (details.delta.dy * widget.slideSpeed);
          setState(() {});
          // print(
          //     '垂直--->update---${widget.size}-->$details-->primaryDelta:${details.primaryDelta}-->_pageOffsetY:${_pageOffsetY}');
        },
        onVerticalDragEnd: (details) {
          // print('垂直--->end--->${details.primaryVelocity}-->$_pageOffsetY');
          _onEndPanVerticalAnimation(details);
        },
        onVerticalDragCancel: () {
          // print('垂直--->cancel--->');
        },
      ),
    );
  }

  @override
  void initState() {
    super.initState();
    _animationControllerY =
        AnimationController(vsync: this, duration: Duration(milliseconds: 300));
    _animationControllerX =
        AnimationController(vsync: this, duration: Duration(milliseconds: 300));

    // 绑定控制器
    if (widget.controller != null && widget.controller is VCardController) {
      widget.controller!.bindState(this);
    }
  }

  @override
  void dispose() {
    super.dispose();
    _animationControllerY.dispose();
    if (widget.controller != null) {
      widget.controller!.dispose();
    }
  }

  @override
  Widget build(BuildContext context) {
    var exOffset = widget.card3Offset;
    Size size = widget.itemSize;
    if (exOffset != null) {
      Offset newOffset = Offset(size.width, size.height) + exOffset;
      size = Size(newOffset.dx, newOffset.dy);
    }
    return ClipRect(
      child: Container(
        width: size.width,
        height: size.height,
        margin: widget.padding,
        child: Stack(
          children: [
            _card4(),
            _card3(),
            _card2(),
            _card1(),
            _card0(),
            if (widget.itemCount > 0 && widget.enablePointer) _gestureView(),
          ],
        ),
      ),
    );
  }
}

class VCardController {
  _VCardViewState? state;

  int get index => state?.frontCardIndex ?? 0;

  void bindState(_VCardViewState state) {
    this.state = state;
  }

  // dispose
  void dispose() {
    state = null;
  }

  // 下一个
  void next() {
    state!._startSlideAnimationY(
      state!._slideAnimation(state!._animationControllerY, 0,
          end: -state!.widget.itemSize.height),
    );
  }

  // 上一个
  void previous() {
    state!._startSlideAnimationY(
      state!._slideAnimation(state!._animationControllerY, 0,
          end: state!.widget.itemSize.height),
    );
  }
}

/// 变化视图，可改缩放、透明度、偏移量
class TransformView extends StatelessWidget {
  final Size size;
  final double? opacity;
  final double? scale;
  final Offset? offset;
  final Widget child;

  const TransformView({
    Key? key,
    required this.size,
    required this.child,
    this.opacity,
    this.scale,
    this.offset,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    Widget tmpWidget = SizedBox.fromSize(
      size: size,
      child: child,
    );

    if (scale != null) {
      tmpWidget = Transform.scale(
        scale: scale!,
        child: tmpWidget,
      );
    }

    if (offset != null) {
      tmpWidget = Transform.translate(
        offset: offset!,
        child: tmpWidget,
      );
    }
    if (opacity != null) {
      tmpWidget = Opacity(
        opacity: opacity!,
        child: tmpWidget,
      );
    }
    return tmpWidget;
  }
}
